package com.shujia.mllib

import org.apache.spark.ml.feature.LabeledPoint
import org.apache.spark.ml.linalg
import org.apache.spark.ml.linalg.Vectors
import org.apache.spark.sql.{DataFrame, SparkSession}

object Demo01Vector {
  def main(args: Array[String]): Unit = {

    /**
     * 向量：有方向 有值
     * 在机器学习中更多指 表示数据的一种方式
     * 机器学习中的各种模型只能够接收 以向量作为格式 的数据
     */
    /**
     * 向量在Spark MLLib中的分类：
     * 1、稠密向量：每个值对应一个特征，会保存所有的值
     * 2、稀疏向量：构建比较复杂，当每条数据的特征大部分为零时可以节省空间
     */
    val denseVec: linalg.Vector = Vectors.dense(Array(1.0, 2.0, 3.0, 4.5, 5.6))
    // [1.0,2.0,3.0,4.5,5.6] 5个值对应5个特征
    println(denseVec)

    val denseVec2: linalg.Vector = Vectors.dense(Array(1.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.0, 4.5, 5.6))

    println(denseVec2)
    println(denseVec2.size)

    // 稀疏向量
    /**
     * 需要接收三个参数：
     * 1、向量的大小
     * 2、有值的index
     * 3、对应值
     */
    val sparseVec: linalg.Vector = Vectors.sparse(44, Array(0, 1, 41, 42, 43), Array(1.0, 2.0, 3.0, 4.5, 5.6))
    println(sparseVec)

    // 稠密向量 跟 稀疏向量之间的转换
    println(denseVec2.toSparse)

    println(sparseVec.toDense)

    // 特征点 label标签 表示数据最终的结果
    val labeledPoint: LabeledPoint = LabeledPoint(1.0, Vectors.dense(1.0, 2.0, 3.0))
    println(labeledPoint)

    // 加载libsvm格式的数据
    // 创建SparkSession
    val spark: SparkSession = SparkSession
      .builder()
      .appName("Demo01Vector")
      .master("local[*]")
      .config("spark.sql.shuffle.partitions", "8")
      .getOrCreate()

    // 1、读取数据 并对数据做特征工程处理
    val imageDF: DataFrame = spark
      .read
      .format("libsvm") // 经过特征工程处理过后的数据
      // 使用libsvm保存数据有可能会造成特征数量的丢失
      .option("numFeatures", 28 * 28)
      .load("Spark/data/mllib/imageFeatures")

    imageDF.show(100)

  }

}
